/* ************************************************ */
/* file cpn.cpp:  contains the main program and     */
/*                network creation routines.        */
/*                                                  */
/* Copyright (c) 1990-98 by Donald R. Tveter        */
/*                                                  */
/* ************************************************ */

#include "cpn.h"

/* built-in C functions */

extern int rand();
extern void srand();

extern WTTYPE rdr(int,REAL,int);
extern int pg(FILE *,char *);
extern REAL readreal(int,REAL,int);
extern int readint(int,int,char);
extern int readch();
extern char *readstr();
extern char *readline();
extern void popfile();
extern int pushfile(char *,int);
extern void parameters(FILE *);
extern int printoutunits(int,LAYER *,int,REAL,char,char);
extern int eval(int,int);
extern int readpats(int,int);
extern int evalone(int,int,int);
extern int printstats(FILE *,int,int,DATA s[2][2]);
extern int loadpat();
extern int run(int,int);
extern void clear();
extern void nullpatterns(int);
extern void kick(WTTYPE,WTTYPE);
extern void nextpat(int);
extern void resetpats(int);
extern void texterror();
extern void help();
extern void restoreweights();
extern void saveweights();
extern void printweights(UNIT *,int);
extern void menus(char);
#if defined(UNIX) && defined(HOTKEYS)
extern void initraw();
#endif

char sysstr[129];     /* string passed to OS with ! command */

int bufferend;        /* index of last character in input line */
int bufferptr;        /* position of next character in buffer */
char buffer[BUFFSIZE];/* holds contents of one input line */
int ch;               /* general purpose character variable */
FILE *copy;           /* file pointer to copy file */
char copyflag;        /* + for copying, - for no copy */
int copyfilecount;    /* to number the copy files */
jmp_buf cmdloopstate; /* to save state in case of a SIGINT */
FILE *data;           /* file for original data */
char *datafile;       /* copy of the data file name saved here */

char echo;            /* controls echoing of characters during input */
char emptystring;     /* for unused string values */

WTTYPE eta;           /* basic learning rate */
WTTYPE eta2;          /* learning rate for lower layers */

char *inputfile;      /* name of file to take extra commands from */
FILE *filestack[MAXFILES];  /* allows for nested reads from files */
int filetimes[MAXFILES];    /* number of times to read file */
int filestackptr;     /* has the index of the current file */
char trfiles[257];    /* contains the data file name */
int format[MAXFORMAT];/* each value in format indicates where to put */
                      /* a blank for compressed output mode or a */
                      /* carriage return for real output */
int timestoread;      /* number of times to read an input file */
char incrementseed;   /* + advances seed, - resets to first value */
char informat;        /* controls format to read numbers */
WTTYPE initrange;     /* initial range of random weights */
WTTYPE kicksize;      /* the minimum size weights that are affected */
WTTYPE kickrange;     /* the range weights are initialized to */

long iotime;          /* time used up printing */
short nlayers;        /* number of layers in network */

LAYER *last;          /* has address of the output layer */
LAYER *start;         /* has address of the input layer */

int lastprint;        /* last iteration pattern responses printed */
int lastsave;         /* last time weights were saved */
int lineno;           /* counts lines for paging */
int maxiter;          /* maximum iterations when not benchmarking */
char outformat;       /* controls format to print output */
char outstr[OUTSTRSIZE]; /* the output string */
int pagesize;         /* size of page for pg */
char runningflag;     /* +/- to print the "running . . ." message */
char probtype;        /* flags general or classification pattern format */
char debugoutput;     /* turns on any debugging code I need */
int prevnpats;        /* previous number of patterns, initially 0 */
int printrate;        /* printrate when not benchmarking */
WTTYPE unknown;       /* value for x in compressed input */

int readerror;        /* flags an error in reading a value */
int readingpattern;   /* flags reading pattern state */
WTTYPE classoff;      /* target value for class off value */
WTTYPE classon;       /* target value for class on value */
char ringbell;        /* flag to ring bell when finished */
int right;            /* number of training patterns learned */
DATA s[2][2];         /* contains stats on pattern learning */
unsigned seed;        /* seed for generating random weights */
SEEDNODE *seedstart;  /* the list of user defined seeds */

char summary;         /* flags summary output mode */
char *testfile;       /* file to take test patterns from */
WTTYPE toler;         /* tolerance based on targets */
REAL toloverall;      /* tolerance based on average error */
REAL totaldiff;
int totaliter;        /* counts total iterations for the program */
char *trainfile;      /* file to take training patterns from */
char up_to_date_stats;/* + does an extra forward pass after update */
int wrong;            /* number of training patterns unlearned */
char wtfilename[FILENAMESIZE]="weights"; /* whole name for weight file */
char *wtfile;         /* base file name for weights file */
int wtfilecount;      /* counts weight files as they are written */
char wtformat;        /* controls format to save and restore weights */
int wttotal;          /* number of weights in the network */
int wtsinuse;         /* number of weights in use */

/* given a layer no. and unit no. locateunit returns the address */
UNIT *locateunit(int layerno,int unitno)
{int i;
 UNIT *u;
 LAYER *layer;
 
if (layerno < 0 || layerno > nlayers)
 {
  pg(stdout,"bad layer number\n");
  return(NULL);
 };
layer = start;
for(i=1;i<=(layerno-1);i++) layer = layer->next;
u = (UNIT *) layer->units;
while (u != NULL && u->unitnumber != unitno) u = u->next;
if (u == NULL)
 {
  sprintf(outstr,"there is no unit %3d in layer %3d\n",unitno,layerno);
  pg(stdout,outstr);
 };
return(u);     
}

LAYER *mklayer(LAYER *prevlayer,int n)
/* creates a layer of n units, pointers */
/* and weights back to the units in the */
/* previous layer and links this new */
/* layer into the list of layers */

{UNIT *front, *p, *q, *bias, *prev, *ptr;
 WTNODE *wfront, *wprev, *w;
 LAYER *lptr;
 int i, j, count;

/* make a list of nodes in this layer */

count = 1;
front = (UNIT *) malloc(sizeof(UNIT));
front->unitnumber = count;
front->layernumber = nlayers;
front->oj = 0;
front->tj = 0;
front->wtlist = NULL;
prev = front;
for(i=1;i<n;i++)
 {
  count = count + 1;
  ptr = (UNIT *) malloc(sizeof(UNIT));
  prev->next = ptr;
  ptr->unitnumber = count;
  ptr->layernumber = nlayers;
  ptr->wtlist = NULL;
  front->oj = 0;
  front->tj = 0;
  prev = ptr;
 };
prev->next = NULL;

/* make a LAYER node to point to this list of units */

lptr = (LAYER *) malloc(sizeof(LAYER));
lptr->unitcount = n;
lptr->patstart[TRAIN] = NULL;
lptr->currentpat[TRAIN] = NULL;
lptr->patstart[TEST] = NULL;
lptr->currentpat[TEST] = NULL;
lptr->backlayer = prevlayer;
lptr->next = NULL;
lptr->units = front;   /* connect the list of units */

/* return if this is the input layer */

if (prevlayer == NULL) return(lptr);
prevlayer->next = lptr;

/* If we are working on a deeper layer, for every node in this layer, */
/* create a linked list back to units in the previous layer. */

i = 1;
q = front;
while (q != NULL) /* do a unit */
 {    
  j = 1;            /* handle first connection */
  p = (UNIT *) prevlayer->units;
  wfront = (WTNODE *) malloc(sizeof(WTNODE));
  wttotal = wttotal + 1;
  q->wtlist = wfront;
  wprev = wfront;
  wfront->backunit = p;
  wfront->weight = 0.0;
  p = p->next;
  while (p != NULL) /* handle rest of connections */
   {
    j = j + 1;
    w = (WTNODE *) malloc(sizeof(WTNODE));
    wttotal = wttotal + 1;
    wprev->next = w;
    w->backunit = p;
    w->weight = 0.0;
    wprev = w;
    p = p->next;
   };
  j = j + 1;
  bias = (UNIT *) malloc(sizeof(UNIT));   /* create a bias unit */
  bias->oj = scale(1.0);
  bias->layernumber = nlayers;
  bias->unitnumber = 32767;           /* bias unit is unit 32767 */
  w = (WTNODE *) malloc(sizeof(WTNODE)); /* connect to end of list */
  wttotal = wttotal + 1;
  wprev->next = w;
  w->backunit = bias;
  w->weight = 0.0;
  w->next = NULL;
  q = q->next;
  i = i + 1;
 };
return(lptr);
}

void init()
{int i,j;
 SEEDNODE *snode;

eta = scale(0.5);
eta2 = eta;
classoff = 0;
classon = scale(1.0);
debugoutput = '-';
inputfile = "(none)";
bufferend = 0;
bufferptr = BUFFSIZE + 1;
ch = ' ';
copyflag = '-';
copyfilecount = 0;
echo = '-';

format[0] = 0;
for(i=1;i<=MAXFORMAT-1;i++) format[i] = format[i-1] + 10;
incrementseed = '-';
informat = 'r';
initrange = scale(1.0);
kickrange = 0;
kicksize = 0;
lastprint = 0;
lastsave = 0;
probtype = 'g';
outformat = 'r';
pagesize = 24;
prevnpats = 0;
printrate = 10;
ringbell = '-';
seedstart = (SEEDNODE *) malloc(sizeof(SEEDNODE));
snode = (SEEDNODE *) malloc(sizeof(SEEDNODE));
seedstart->next = snode;
snode->val = 0;
srand(0);
snode->next = NULL;
for (i=TRAIN;i<=TEST;i++) for (j=TOL;j<=MAX;j++)
 {
  s[j][i].npats = 0;
  s[j][i].iterno = 0;
  s[j][i].right = 0;
  s[j][i].wrong = 0;
  s[j][i].avgerr = 0.0;
  s[j][i].pctright = 0.0;
 };
sysstr[0] = '\0';
summary = '+';
timestoread = 1;
toler = scale(0.1);
trfiles[0] = '\0';
unknown = scale(0.5);
up_to_date_stats = '-';
wtfilecount = 0;
wtfile = "weights";
runningflag = '+';
wtformat = 'r';
wttotal = 0;
maxiter = 100;
}

int nonetwork()
{
if (start != NULL) return(0);
pg(stdout,"there is no network\n");
return(1);
}

int nopatterns()
{
if (s[TOL][TRAIN].npats != 0) return(0);
pg(stdout,"there are no patterns\n");
return(1);
}

/* for a SIGINT, restart in cmdloop */
void restartcmdloop(int dummy)
{
while (data != stdin) popfile();
signal(SIGINT,restartcmdloop);
longjmp(cmdloopstate,1);
}
 
void cmdloop()    /* read commands and process them */
{
int finished, layerno, unitno, layer1, layer2, node1, node2;
int i, itemp, itemp2;
WTTYPE temp, temp2, *target;
PATLIST *pl;
REAL rtemp;
LAYER *p;
UNIT *u, *n1, *n2;
WTNODE *w;
SEEDNODE *snode, *sprev;

setjmp(cmdloopstate); /* restart here from SIGINT */
finished = 0;
do{
   if (data == stdin) pg(stdout,"[ACFMNPTW?!cefhlmopqrstw]? ");
   if (data == stdin) lineno = 0;
   while(ch == ' ' || ch == '\n') ch = readch();
   switch (ch) {

case EOF:
popfile();
if (data == stdin) pg(stdout,"taking commands from stdin now\n");
break;

case '?': menus('?'); break;

case '!':
i = 0;
do ch = readch(); while (ch == ' ');
if (ch == '\n')
 {
  system(sysstr);
  break;
 }
else if (ch == '"') break; /* loading string but not executing */
while ((ch != '\n' && ch != '"') && i <= 80)
 {
  sysstr[i] = ch;
  ch = readch();
  i = i + 1;
 };
if (ch == '"') sysstr[i-1] = '\0';
else
 {
  sysstr[i] = '\0';
  system(sysstr);
 };
bufferptr = bufferptr - 1;
break;

case '*': break;  /* * on a line is a comment */

case 'c': {int initialize;
if (nonetwork()) goto endc;
initialize = 0;
do ch = readch(); while (ch == ' ');
if (ch == '\n' || ch == '*') goto clearnet;
else if (ch == 'i')
 {
  initialize = 1;
  do ch = readch(); while (ch == ' ');
  if (ch == '\n' || ch == '*') goto clearnet;
  else
     {
      bufferptr = bufferptr - 1;
      temp2 = rdr(GE,scale(0.0),'c');
      if (readerror) goto endc;
      initrange = temp2;
     };
 };

clearnet:
clear();
srand(seed);
if (initialize == 1)
 {
  kick((WTTYPE) 0,initrange);
  sprintf(outstr,"seed = %d, range = -%5.2f to +%5.2f\n",seed,
          unscale(initrange), unscale(initrange));
  pg(stdout,outstr);
 }
else {sprintf(outstr,"seed = %d\n",seed); pg(stdout,outstr);};
endc: break;};

case 'e':
temp = rdr(GE,0.0,'e');
if (!readerror) eta = temp;
do ch = readch(); while (ch == ' ');
bufferptr = bufferptr - 1;
if (ch != '\n' && ch != '*')
 {
  temp = rdr(GE,0.0,'r');
  if (!readerror) eta2 = temp;
 }
else eta2 = eta;
break;

case 'f':
while (ch != '\n' && ch != '*')
 {
  ch = readch();
  if (ch == 'B')
   {
    itemp = 0;
    do ch = readch(); while (ch == ' ');
    while (ch >= '1' && ch <= '9')
     {
      bufferptr = bufferptr - 1;
      itemp2 = readint(format[itemp],MAXINT,'f');
      if (readerror) goto endf;
      itemp = itemp + 1;
      if (itemp < MAXFORMAT) format[itemp] = itemp2;
      else pg(stdout,"format too long\n");
      do ch = readch(); while (ch == ' ');
     };
    if (itemp < MAXFORMAT-1)
       for (i=itemp+1;i<=MAXFORMAT-1; i++) format[i] = format[i-1] + 10;
   }
  else if (ch == 'b')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == '+' || ch == '-') ringbell = ch; else texterror();
   }
  else if (ch == 'c')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == '+')
     {
      if (copy != NULL) fflush(copy);
      else copy = fopen("copy","w");
      if (copy == NULL)
       {sprintf(outstr,"cannot open file:  %s\n",outstr); pg(stdout,outstr); };
      copyflag = '+';
     }
    else if (ch == '-')
     {
      copyflag = '-';
      if (copy != NULL)
       {
        fflush(copy);
        fclose(copy);
       }
     }
    else texterror();
   }
  else if (ch == 'd')
   {/* with fd+ I can turn on a piece of debugging code (if it exists) */
    do ch = readch(); while (ch == ' ');
    if (ch == '+' || ch == '-') debugoutput = ch;
    else
     {
      texterror();
      goto endf;
     }
   }
  else if (ch == 'e')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == '+' || ch == '-') echo = ch;
   }
  else if (ch == 'i')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == 'c' || ch == 'r') informat = ch; else texterror();
   }
  else if (ch == 'o')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == 'a' || ch == 'c' || ch == 'r' || ch == 'e')
       outformat = ch;
    else texterror();
   }
  else if (ch == 'P')
   {
    itemp = readint(0,MAXINT,'f');
    if (!readerror) pagesize = itemp;
   }
  else if (ch == 'p')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == 'c' || ch == 'g') probtype = ch;
    else texterror();
   }
  else if (ch == 'R')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == '+' || ch == '-') runningflag = ch;
    else texterror();
   }
  else if (ch == 's')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == '+' || ch == '-') summary = ch;
    else texterror();
   }
  else if (ch == 'x')
   {
    temp = rdr(GT,(REAL) -MAXINT,'f');
    if (!readerror) unknown = temp;
   }
  else if (ch == ' ' || ch == '*' || ch == '\n');
  else texterror();
 }
bufferptr = bufferptr - 1;
endf:
break;

case 'h': help(); break;

case 'l':
if (nonetwork()) break;
layerno = readint(1,nlayers,'l'); 
if (readerror) break;
p = start;
for (i=2;i<=layerno;i++) p = p->next;
printoutunits(0,p,-1,0.0,(char) 0,(char) 0);
break;

/* make a network */

case 'm': {LAYER *layer; int itemp, itemp2;
nlayers = 0;
wttotal = 0;
ch = readch();
p = NULL;
while (ch != '\n' && ch != '*')
 {
  itemp = readint(1,MAXINT,'m');
  if (readerror)
   {
    wttotal = 0;
    start = NULL;
    goto endm;
   };
  nlayers = nlayers + 1;
  p = mklayer(p,itemp);
  if (nlayers == 1) start = p;
  ch = readch();
  while (ch == ' ') ch = readch();
  if (ch >= '0' && ch <= '9') bufferptr = bufferptr - 1;
 };
last = p;

wtsinuse = wttotal;
bufferptr = bufferptr - 1;
nullpatterns(TRAIN);
nullpatterns(TEST);
/* should really free up the old network structure as well */
layer = last->backlayer;
clear();
endm: break;};

case 'o':
do ch = readch(); while (ch == ' ');
 {
  PATNODE *targetpn;
  bufferptr = bufferptr - 1; /* unget the character */
  if (nonetwork() || nopatterns()) break;
  itemp = readint(1,s[TOL][TRAIN].npats,'o');
  if (readerror) break;
  resetpats(TRAIN);
  for (i=1;i<=itemp;i++) nextpat(TRAIN);
  /* setoutputpat(); */
  u = (UNIT *) last->units;
  pl = last->currentpat[TRAIN];
  targetpn = pl->pats;
  itemp2 = 0; /* unit counter */
  i = 1;      /* format counter */
  while (u != NULL)
   {
    sprintf(outstr,"%5.2f",unscale(targetpn->val)); pg(stdout,outstr);
    targetpn++;
    itemp2 = itemp2 + 1;
    if (format[i] == itemp2)
     {
      if (outformat == 'r') pg(stdout,"\n"); else pg(stdout," ");
      if (i < MAXFORMAT - 1) i = i + 1;
     };
    u = u->next;
   }
  pg(stdout,"\n");
 };
endo:
break;

case 'p':
do ch = readch(); while (ch == ' ');
bufferptr = bufferptr - 1;
if (ch == 'a' || ch == '\n' || ch == '*')
 {int stopprinting;
  if (nonetwork() || nopatterns()) break;
  stopprinting = eval(TRAIN,1);
  if (!stopprinting) printstats(stdout,TRAIN,0,s);
 }
else
 {
  itemp = readint(0,s[TOL][TRAIN].npats,'p');
  if (readerror) break;
  if (nonetwork() || nopatterns()) break;
  if (itemp == 0) {eval(TRAIN,0); printstats(stdout,TRAIN,0,s);}
  else evalone(itemp,TRAIN,1);
 };
break;

case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'x':
case '-':
case '\\': {int status;
if (nonetwork()) break;
if (ch != '\\') bufferptr = bufferptr - 1;
status = loadpat();
if (status == 1) printoutunits(0,last,-1,0.0,(char) 0,(char) 0);
break;}

case 'q': finished = 1; break;

case 'r': /* r for run, rw for restore weights */
do ch = readch(); while (ch == ' ');
if (ch == '\n' || ch == '*')
 {
  if (nonetwork() || nopatterns()) goto endr;
  run(maxiter,printrate);
 }
else if (ch == 'w')
 {
  do ch = readch(); while (ch == ' ');
  bufferptr = bufferptr - 1;
  if (ch == '*' || ch == '\n') /* nothing */ ;
  else
   {
    //wtfile = readstr();
	wtfile = readline();
    strcpy(wtfilename,wtfile);
   };
  if (nonetwork()) break; else restoreweights();
 }
else if (ch == 't')
 {
  do ch = readch(); while (ch == ' ');
  if (ch == '{') {/* nothing */}
  else
   {
    bufferptr = bufferptr - 1;
	trainfile = readline();
    itemp = MAXINT;
    if (!pushfile(trainfile,1)) goto endr;
    strcat(trfiles,"rt ");
    strcat(trfiles,trainfile);
    strcat(trfiles,"\n");
   };
  nullpatterns(TRAIN);
  readingpattern = 1;
  itemp2 = readpats(TRAIN,'r');
  readingpattern = 0;
  s[TOL][TRAIN].npats = itemp2;
  s[MAX][TRAIN].npats = itemp2;
  sprintf(outstr,"%d training patterns read\n\n",itemp2); pg(stdout,outstr);
  goto endr;
 }
else if (ch >= '1' && ch <= '9')
 {
  bufferptr = bufferptr - 1;
  itemp = readint(1,MAXINT,'r'); 
  if (!readerror) maxiter = itemp; else goto endr;
  itemp = readint(1,MAXINT,'r');
  if (!readerror) printrate = itemp; else goto endr;
  do ch = readch(); while (ch == ' ');
  if (ch == '"') goto endr; else bufferptr = bufferptr - 1;
  if (!nonetwork() && !nopatterns()) run(maxiter,printrate);
 }
else texterror();
endr:
break;

case 's':  /* s <int> for seed, sw <filename> for save weights */
do ch = readch(); while (ch == ' ');
if (ch == 'w')
 {
  do ch = readch(); while (ch == ' ');
  bufferptr = bufferptr - 1;
  if (ch == '*' || ch == '\n') /* nothing */ ; else wtfile = /*readstr()*/readline();
  if (nonetwork()) break; else saveweights();
 }
else if (ch == 'i' || (ch >= '0' && ch <= '9'))
 {
  bufferptr = bufferptr - 1;
  sprev = seedstart;
  while (ch != '\n' && ch != '*')
   {
    do ch = readch(); while (ch == ' ');
    if (ch == 'i')
     {
      do ch = readch(); while (ch == ' ');
      if (ch == '+' || ch == '-') incrementseed = ch;
      else {texterror(); goto ends;};
     }
    else if (ch >= '0' && ch <= '9')
     {
      bufferptr = bufferptr - 1;
      seed = readint(0,MAXINT,'s');
      if (readerror) goto ends;
      snode = (SEEDNODE *) malloc(sizeof(SEEDNODE));
      snode->val = seed;
      snode->next = NULL;
      sprev->next = snode;
      sprev = snode;
     }
    else if (ch == '\n' || ch == '*');
    else {texterror(); goto ends;};
   };
  snode = seedstart->next;
  seed = snode->val;
 }
else texterror();
ends:
endsw:
break;

case 't':
do ch = readch(); while (ch == ' ');
if ((ch == 'a' || ch == '\n' || ch == '*') && (!nonetwork()))
 {
  if (s[TOL][TEST].npats == 0) pg(stdout,"no test patterns\n");
  else
   {
    eval(TEST,1);
    printstats(stdout,TEST,0,s);
    bufferptr = bufferptr - 1;
   };
 }
else if (ch == 'o')
 {
  rtemp = readreal(GE,0.0,'t');
  if (readerror) break;
  toloverall = rtemp;
 }
else if (ch == 'f')
 {
  do ch = readch(); while (ch == ' ');
  bufferptr = bufferptr - 1;
  //testfile = readstr();
  testfile = readline();
  nullpatterns(TEST);
  if (!pushfile(testfile,1)) goto endt;
  readingpattern = 1;
  itemp = readpats(TEST,'t');
  readingpattern = 0;
  sprintf(outstr,"%d test patterns read\n",itemp); pg(stdout,outstr);
  s[TOL][TEST].npats = itemp;
  s[MAX][TEST].npats = itemp;
 }
else
 {
  bufferptr = bufferptr - 1;
  rtemp = readreal(GE,0.0,'t');
  if (readerror) break;
  else if (rtemp > 0 && rtemp < 1.0) toler = scale(rtemp);
  else
   {
    bufferptr = bufferptr - 1;
    if (s[TOL][TEST].npats == 0)
     {
      pg(stdout,"there is no test set\n");
      break;
     };
    if (rtemp == 0.0) {eval(TEST,0); printstats(stdout,TEST,0,s);}
    else
     {
      itemp = (int) rtemp;
      if (itemp > s[TOL][TEST].npats)
       pg(stdout,"not that many patterns in the test set\n");
      else evalone(itemp,TEST,1);
     };
   };
 };
endt: break;

case 'w':
{int i;
 if (nonetwork()) break;
 layerno = readint(2,nlayers,'w');
 if (readerror) break;
 unitno = readint(1,MAXINT,'w');
 if (readerror) break;
 u = locateunit(layerno,unitno);
 if (u != NULL) printweights(u,layerno);
 break;
};

default: if (ch >= 'A' && ch <= 'Z') menus(ch); else texterror();
break;
      };
    if (ch != '\n') do ch = readch(); while (ch != '\n');
  }while (!finished);
}

void main(int argc,char *argv[])
{
setbuf(stdout,NULL);  /* set unbuffered output */
#if defined(UNIX) && defined(HOTKEYS)
initraw();
#endif
lineno = 0;
filestackptr = 0;
filestack[0] = stdin;
data = stdin;
emptystring = '\0';
trainfile = &emptystring;
testfile = &emptystring;
if (argc == 1)
 {
  printf("no data file, stdin assumed\n");
  datafile = "stdin";
 }
else
 {
  datafile = argv[1];
  pushfile(datafile,1);
 };
init();
signal(SIGINT,restartcmdloop); /* restart from interrupt */
cmdloop();
if (copy != NULL)
 {
  fflush(copy);
  fclose(copy);
 }
}
